﻿// =====================================================================
//  This file is part of the Microsoft Dynamics CRM SDK code samples.
//
//  Copyright (C) Microsoft Corporation.  All rights reserved.
//
//  This source code is intended only as a supplement to Microsoft
//  Development Tools and/or on-line documentation.  See these other
//  materials for detailed information regarding Microsoft code samples.
//
//  THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//  PARTICULAR PURPOSE.
// =====================================================================

//<snippetSDK.Metadata.js>

SDK = window.SDK || { __namespace: true };
SDK.Metadata = SDK.Metadata || { __namespace: true };

(function () {


    this.RetrieveAllEntities = function (EntityFilters, RetrieveAsIfPublished, successCallBack, errorCallBack, passThroughObject) {
        ///<summary>
        /// Sends an asynchronous RetrieveAllEntities Request to retrieve all entities in the system
        ///</summary>
        ///<returns>entityMetadataCollection</returns>
        ///<param name="EntityFilters" type="Number">
        /// SDK.Metadata.EntityFilters provides an enumeration for the filters available to filter which data is retrieved.
        /// Include only those elements of the entity you want to retrieve. Retrieving all parts of all entitities may take significant time.
        ///</param>
        ///<param name="RetrieveAsIfPublished" type="Boolean">
        /// Sets whether to retrieve the metadata that has not been published.
        ///</param>
        ///<param name="successCallBack" type="Function">
        /// The function that will be passed through and be called by a successful response.
        /// This function must accept the entityMetadataCollection as a parameter.
        ///</param>
        ///<param name="errorCallBack" type="Function">
        /// The function that will be passed through and be called by a failed response.
        /// This function must accept an Error object as a parameter.
        ///</param>
        ///<param name="passThroughObject" optional="true"  type="Object">
        /// An Object that will be passed through to as the second parameter to the successCallBack.
        ///</param>
        if ((typeof EntityFilters != "number") || (EntityFilters < 1 || EntityFilters > 15))
        { throw new Error("SDK.Metadata.RetrieveAllEntities EntityFilters must be a SDK.Metadata.EntityFilters value."); }
        if (typeof RetrieveAsIfPublished != "boolean")
        { throw new Error("SDK.Metadata.RetrieveAllEntities RetrieveAsIfPublished must be a boolean value."); }
        if (typeof successCallBack != "function")
        { throw new Error("SDK.Metadata.RetrieveAllEntities successCallBack must be a function."); }
        if (typeof errorCallBack != "function")
        { throw new Error("SDK.Metadata.RetrieveAllEntities errorCallBack must be a function."); }

        var entityFiltersValue = _evaluateEntityFilters(EntityFilters);

        var request = [
        "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">",
         "<soapenv:Body>",
          "<Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">",
           "<request i:type=\"a:RetrieveAllEntitiesRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\">",
            "<a:Parameters xmlns:b=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">",
             "<a:KeyValuePairOfstringanyType>",
              "<b:key>EntityFilters</b:key>",
              "<b:value i:type=\"c:EntityFilters\" xmlns:c=\"http://schemas.microsoft.com/xrm/2011/Metadata\">" + _xmlEncode(entityFiltersValue) + "</b:value>",
             "</a:KeyValuePairOfstringanyType>",
             "<a:KeyValuePairOfstringanyType>",
              "<b:key>RetrieveAsIfPublished</b:key>",
              "<b:value i:type=\"c:boolean\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">" + _xmlEncode(RetrieveAsIfPublished.toString()) + "</b:value>",
             "</a:KeyValuePairOfstringanyType>",
            "</a:Parameters>",
            "<a:RequestId i:nil=\"true\" />",
            "<a:RequestName>RetrieveAllEntities</a:RequestName>",
          "</request>",
         "</Execute>",
        "</soapenv:Body>",
        "</soapenv:Envelope>"].join("");
        var req = new XMLHttpRequest();
        req.open("POST", _getUrl() + "/XRMServices/2011/Organization.svc/web", true);
        try { req.responseType = 'msxml-document' } catch (e) { }
        req.setRequestHeader("Accept", "application/xml, text/xml, */*");
        req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
        req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
        req.onreadystatechange = function () {
            if (req.readyState == 4 /* complete */) {
                req.onreadystatechange = null; //Addresses potential memory leak issue with IE
                if (req.status == 200) {
                    //Success				
                    var doc = req.responseXML;
                    try { _setSelectionNamespaces(doc); } catch (e) { }
                    var entityMetadataNodes = _selectNodes(doc, "//c:EntityMetadata");
                    var entityMetadataCollection = [];
                    for (var i = 0; i < entityMetadataNodes.length; i++) {
                        var a = _objectifyNode(entityMetadataNodes[i]);
                        a._type = "EntityMetadata";
                        entityMetadataCollection.push(a);
                    }

                    successCallBack(entityMetadataCollection, passThroughObject);
                }
                else {
                    errorCallBack(_getError(req));
                }
            }
        };
        req.send(request);

    };

    this.RetrieveEntity = function (EntityFilters, LogicalName, MetadataId, RetrieveAsIfPublished, successCallBack, errorCallBack, passThroughObject) {
        ///<summary>
        /// Sends an asynchronous RetrieveEntity Request to retrieve a specific entity
        ///</summary>
        ///<returns>entityMetadata</returns>
        ///<param name="EntityFilters" type="Number">
        /// SDK.Metadata.EntityFilters provides an enumeration for the filters available to filter which data is retrieved.
        /// Include only those elements of the entity you want to retrieve. Retrieving all parts of all entitities may take significant time.
        ///</param>
        ///<param name="LogicalName" optional="true" type="String">
        /// The logical name of the entity requested. A null value may be used if a MetadataId is provided.
        ///</param>
        ///<param name="MetadataId" optional="true" type="String">
        /// A null value or an empty guid may be passed if a LogicalName is provided.
        ///</param>
        ///<param name="RetrieveAsIfPublished" type="Boolean">
        /// Sets whether to retrieve the metadata that has not been published.
        ///</param>
        ///<param name="successCallBack" type="Function">
        /// The function that will be passed through and be called by a successful response.
        /// This function must accept the entityMetadata as a parameter.
        ///</param>
        ///<param name="errorCallBack" type="Function">
        /// The function that will be passed through and be called by a failed response.
        /// This function must accept an Error object as a parameter.
        ///</param>
        ///<param name="passThroughObject" optional="true"  type="Object">
        /// An Object that will be passed through to as the second parameter to the successCallBack.
        ///</param>
        if ((typeof EntityFilters != "number") || (EntityFilters < 1 || EntityFilters > 15))
        { throw new Error("SDK.Metadata.RetrieveEntity EntityFilters must be a SDK.Metadata.EntityFilters value."); }
        if (LogicalName == null && MetadataId == null) {
            throw new Error("SDK.Metadata.RetrieveEntity requires either the LogicalName or MetadataId parameter not be null.");
        }
        if (LogicalName != null) {
            if (typeof LogicalName != "string")
            { throw new Error("SDK.Metadata.RetrieveEntity LogicalName must be a string value."); }
            MetadataId = "00000000-0000-0000-0000-000000000000";
        }
        if (MetadataId != null && LogicalName == null) {
            if (typeof MetadataId != "string")
            { throw new Error("SDK.Metadata.RetrieveEntity MetadataId must be a string value."); }
        }
        if (typeof RetrieveAsIfPublished != "boolean")
        { throw new Error("SDK.Metadata.RetrieveEntity RetrieveAsIfPublished must be a boolean value."); }
        if (typeof successCallBack != "function")
        { throw new Error("SDK.Metadata.RetrieveEntity successCallBack must be a function."); }
        if (typeof errorCallBack != "function")
        { throw new Error("SDK.Metadata.RetrieveEntity errorCallBack must be a function."); }
        var entityFiltersValue = _evaluateEntityFilters(EntityFilters);

        var entityLogicalNameValueNode = "";
        if (LogicalName == null)
        { entityLogicalNameValueNode = "<b:value i:nil=\"true\" />"; }
        else
        { entityLogicalNameValueNode = "<b:value i:type=\"c:string\"   xmlns:c=\"http://www.w3.org/2001/XMLSchema\">" + _xmlEncode(LogicalName.toLowerCase()) + "</b:value>"; }
        var request = [
        "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">",
         "<soapenv:Body>",
          "<Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">",
           "<request i:type=\"a:RetrieveEntityRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\">",
            "<a:Parameters xmlns:b=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">",
             "<a:KeyValuePairOfstringanyType>",
              "<b:key>EntityFilters</b:key>",
              "<b:value i:type=\"c:EntityFilters\" xmlns:c=\"http://schemas.microsoft.com/xrm/2011/Metadata\">" + _xmlEncode(entityFiltersValue) + "</b:value>",
             "</a:KeyValuePairOfstringanyType>",
             "<a:KeyValuePairOfstringanyType>",
              "<b:key>MetadataId</b:key>",
              "<b:value i:type=\"ser:guid\"  xmlns:ser=\"http://schemas.microsoft.com/2003/10/Serialization/\">" + _xmlEncode(MetadataId) + "</b:value>",
             "</a:KeyValuePairOfstringanyType>",
             "<a:KeyValuePairOfstringanyType>",
              "<b:key>RetrieveAsIfPublished</b:key>",
              "<b:value i:type=\"c:boolean\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">" + _xmlEncode(RetrieveAsIfPublished.toString()) + "</b:value>",
             "</a:KeyValuePairOfstringanyType>",
             "<a:KeyValuePairOfstringanyType>",
              "<b:key>LogicalName</b:key>",
               entityLogicalNameValueNode,
             "</a:KeyValuePairOfstringanyType>",
            "</a:Parameters>",
            "<a:RequestId i:nil=\"true\" />",
            "<a:RequestName>RetrieveEntity</a:RequestName>",
           "</request>",
          "</Execute>",
         "</soapenv:Body>",
        "</soapenv:Envelope>"].join("");
        var req = new XMLHttpRequest();
        req.open("POST", _getUrl() + "/XRMServices/2011/Organization.svc/web", true);
        try { req.responseType = 'msxml-document' } catch (e) { }
        req.setRequestHeader("Accept", "application/xml, text/xml, */*");
        req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
        req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
        req.onreadystatechange = function () {
            if (req.readyState == 4 /* complete */) {
                req.onreadystatechange = null; //Addresses potential memory leak issue with IE
                if (req.status == 200) {
                    var doc = req.responseXML;
                    try { _setSelectionNamespaces(doc); } catch (e) { }
                    var a = _objectifyNode(_selectSingleNode(doc, "//b:value"));
                    a._type = "EntityMetadata";
                    successCallBack(a, passThroughObject);
                }
                else {
                    //Failure
                    errorCallBack(_getError(req));
                }
            }

        };
        req.send(request);


    };

    this.RetrieveAttribute = function (EntityLogicalName, LogicalName, MetadataId, RetrieveAsIfPublished, successCallBack, errorCallBack, passThroughObject) {
        ///<summary>
        /// Sends an asynchronous RetrieveAttribute Request to retrieve a specific entity
        ///</summary>
        ///<returns>AttributeMetadata</returns>
        ///<param name="EntityLogicalName"  optional="true" type="String">
        /// The logical name of the entity for the attribute requested. A null value may be used if a MetadataId is provided.
        ///</param>
        ///<param name="LogicalName" optional="true" type="String">
        /// The logical name of the attribute requested. 
        ///</param>
        ///<param name="MetadataId" optional="true" type="String">
        /// A null value may be passed if an EntityLogicalName and LogicalName is provided.
        ///</param>
        ///<param name="RetrieveAsIfPublished" type="Boolean">
        /// Sets whether to retrieve the metadata that has not been published.
        ///</param>
        ///<param name="successCallBack" type="Function">
        /// The function that will be passed through and be called by a successful response.
        /// This function must accept the entityMetadata as a parameter.
        ///</param>
        ///<param name="errorCallBack" type="Function">
        /// The function that will be passed through and be called by a failed response.
        /// This function must accept an Error object as a parameter.
        ///</param>
        ///<param name="passThroughObject" optional="true"  type="Object">
        /// An Object that will be passed through to as the second parameter to the successCallBack.
        ///</param>
        if (EntityLogicalName == null && LogicalName == null && MetadataId == null) {
            throw new Error("SDK.Metadata.RetrieveAttribute requires either the EntityLogicalName and LogicalName  parameters or the MetadataId parameter not be null.");
        }
        if (MetadataId != null && EntityLogicalName == null && LogicalName == null) {
            if (typeof MetadataId != "string")
            { throw new Error("SDK.Metadata.RetrieveEntity MetadataId must be a string value."); }
        }
        else { MetadataId = "00000000-0000-0000-0000-000000000000"; }
        if (EntityLogicalName != null) {
            if (typeof EntityLogicalName != "string") {
                { throw new Error("SDK.Metadata.RetrieveAttribute EntityLogicalName must be a string value."); }
            }
        }
        if (LogicalName != null) {
            if (typeof LogicalName != "string") {
                { throw new Error("SDK.Metadata.RetrieveAttribute LogicalName must be a string value."); }
            }

        }
        if (typeof RetrieveAsIfPublished != "boolean")
        { throw new Error("SDK.Metadata.RetrieveAttribute RetrieveAsIfPublished must be a boolean value."); }
        if (typeof successCallBack != "function")
        { throw new Error("SDK.Metadata.RetrieveAttribute successCallBack must be a function."); }
        if (typeof errorCallBack != "function")
        { throw new Error("SDK.Metadata.RetrieveAttribute errorCallBack must be a function."); }

        var entityLogicalNameValueNode;
        if (EntityLogicalName == null) {
            entityLogicalNameValueNode = "<b:value i:nil=\"true\" />";
        }
        else {
            entityLogicalNameValueNode = "<b:value i:type=\"c:string\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">" + _xmlEncode(EntityLogicalName.toLowerCase()) + "</b:value>";
        }
        var logicalNameValueNode;
        if (LogicalName == null) {
            logicalNameValueNode = "<b:value i:nil=\"true\" />";
        }
        else {
            logicalNameValueNode = "<b:value i:type=\"c:string\"   xmlns:c=\"http://www.w3.org/2001/XMLSchema\">" + _xmlEncode(LogicalName.toLowerCase()) + "</b:value>";
        }
        var request = [
        "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">",
         "<soapenv:Body>",
          "<Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">",
           "<request i:type=\"a:RetrieveAttributeRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\">",
            "<a:Parameters xmlns:b=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">",
             "<a:KeyValuePairOfstringanyType>",
              "<b:key>EntityLogicalName</b:key>",
               entityLogicalNameValueNode,
             "</a:KeyValuePairOfstringanyType>",
             "<a:KeyValuePairOfstringanyType>",
              "<b:key>MetadataId</b:key>",
              "<b:value i:type=\"ser:guid\"  xmlns:ser=\"http://schemas.microsoft.com/2003/10/Serialization/\">" + _xmlEncode(MetadataId) + "</b:value>",
             "</a:KeyValuePairOfstringanyType>",
              "<a:KeyValuePairOfstringanyType>",
              "<b:key>RetrieveAsIfPublished</b:key>",
            "<b:value i:type=\"c:boolean\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">" + _xmlEncode(RetrieveAsIfPublished.toString()) + "</b:value>",
             "</a:KeyValuePairOfstringanyType>",
             "<a:KeyValuePairOfstringanyType>",
              "<b:key>LogicalName</b:key>",
               logicalNameValueNode,
             "</a:KeyValuePairOfstringanyType>",
            "</a:Parameters>",
            "<a:RequestId i:nil=\"true\" />",
            "<a:RequestName>RetrieveAttribute</a:RequestName>",
           "</request>",
          "</Execute>",
         "</soapenv:Body>",
        "</soapenv:Envelope>"].join("");
        var req = new XMLHttpRequest();
        req.open("POST", _getUrl() + "/XRMServices/2011/Organization.svc/web", true);
        req.setRequestHeader("Accept", "application/xml, text/xml, */*");
        req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
        req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
        req.onreadystatechange = function () {
            if (req.readyState == 4 /* complete */) {
                req.onreadystatechange = null; //Addresses potential memory leak issue with IE
                if (req.status == 200) {
                    //Success
                    var doc = req.responseXML;
                    try { _setSelectionNamespaces(doc); } catch (e) { }
                    var a = _objectifyNode(_selectSingleNode(doc, "//b:value"));

                    successCallBack(a, passThroughObject);
                }
                else {
                    //Failure
                    errorCallBack(_getError(req));
                }
            }
        };
        req.send(request);


    };

    this.EntityFilters = function () {
        /// <summary>SDK.Metadata.EntityFilters enum summary</summary>
        /// <field name="Default" type="Number" static="true">enum field summary for Default</field>
        /// <field name="Entity" type="Number" static="true">enum field summary for Entity</field>
        /// <field name="Attributes" type="Number" static="true">enum field summary for Attributes</field>
        /// <field name="Privileges" type="Number" static="true">enum field summary for Privileges</field>
        /// <field name="Relationships" type="Number" static="true">enum field summary for Relationships</field>
        /// <field name="All" type="Number" static="true">enum field summary for All</field>
        throw new Error("Constructor not implemented this is a static enum.");
    };



    var _arrayElements = ["Attributes",
     "ManyToManyRelationships",
     "ManyToOneRelationships",
     "OneToManyRelationships",
     "Privileges",
     "LocalizedLabels",
     "Options",
     "Targets"];

    function _getError(resp) {
        ///<summary>
        /// Private function that attempts to parse errors related to connectivity or WCF faults.
        ///</summary>
        ///<param name="resp" type="XMLHttpRequest">
        /// The XMLHttpRequest representing failed response.
        ///</param>

        //Error descriptions come from http://support.microsoft.com/kb/193625
        if (resp.status == 12029)
        { return new Error("The attempt to connect to the server failed."); }
        if (resp.status == 12007)
        { return new Error("The server name could not be resolved."); }
        var faultXml = resp.responseXML;
        var errorMessage = "Unknown (unable to parse the fault)";
        if (typeof faultXml == "object") {

            var faultstring = null;
            var ErrorCode = null;

            var bodyNode = faultXml.firstChild.firstChild;

            //Retrieve the fault node
            for (var i = 0; i < bodyNode.childNodes.length; i++) {
                var node = bodyNode.childNodes[i];

                //NOTE: This comparison does not handle the case where the XML namespace changes
                if ("s:Fault" == node.nodeName) {
                    for (var j = 0; j < node.childNodes.length; j++) {
                        var testNode = node.childNodes[j];
                        if ("faultstring" == testNode.nodeName) {
                            faultstring = _getNodeText(testNode);
                        }
                        if ("detail" == testNode.nodeName) {
                            for (var k = 0; k < testNode.childNodes.length; k++) {
                                var orgServiceFault = testNode.childNodes[k];
                                if ("OrganizationServiceFault" == orgServiceFault.nodeName) {
                                    for (var l = 0; l < orgServiceFault.childNodes.length; l++) {
                                        var ErrorCodeNode = orgServiceFault.childNodes[l];
                                        if ("ErrorCode" == ErrorCodeNode.nodeName) {
                                            ErrorCode = _getNodeText(ErrorCodeNode);
                                            break;
                                        }
                                    }
                                }
                            }

                        }
                    }
                    break;
                }

            }
        }
        if (ErrorCode != null && faultstring != null) {
            errorMessage = "Error Code:" + ErrorCode + " Message: " + faultstring;
        }
        else {
            if (faultstring != null) {
                errorMessage = faultstring;
            }
        }
        return new Error(errorMessage);
    };

    function _Context() {
        var errorMessage = "Context is not available.";
        if (typeof GetGlobalContext != "undefined")
        { return GetGlobalContext(); }
        else {
            if (typeof Xrm != "undefined") {
                return Xrm.Page.context;
            }
            else { return new Error(errorMessage); }
        }
    };

    function _getUrl() {      
        if (typeof _Context().getClientUrl() != "undefined") {
            return _Context().getClientUrl();
        }

        var url = _Context().getServerUrl();
        if (url.match(/\/$/)) {
            url = url.substring(0, url.length - 1);
        }
        return url;
    };

    function _evaluateEntityFilters(EntityFilters) {
        var entityFilterArray = [];
        if ((1 & EntityFilters) == 1) {
            entityFilterArray.push("Entity");
        }
        if ((2 & EntityFilters) == 2) {
            entityFilterArray.push("Attributes");
        }
        if ((4 & EntityFilters) == 4) {
            entityFilterArray.push("Privileges");
        }
        if ((8 & EntityFilters) == 8) {
            entityFilterArray.push("Relationships");
        }
        return entityFilterArray.join(" ");
    };

    function _isMetadataArray(elementName) {
        for (var i = 0; i < _arrayElements.length; i++) {
            if (elementName == _arrayElements[i]) {
                return true;
            }
        }
        return false;
    };

    function _objectifyNode(node) {
        //Check for null
        if (node.attributes != null && node.attributes.length == 1) {
            if (node.attributes.getNamedItem("i:nil") != null && node.attributes.getNamedItem("i:nil").nodeValue == "true") {
                return null;
            }
        }

        //Check if it is a value
        if ((node.firstChild != null) && (node.firstChild.nodeType == 3)) {
            var nodeName = _getNodeName(node);

            switch (nodeName) {
                //Integer Values 
                case "ActivityTypeMask":
                case "ObjectTypeCode":
                case "ColumnNumber":
                case "DefaultFormValue":
                case "MaxValue":
                case "MinValue":
                case "MaxLength":
                case "Order":
                case "Precision":
                case "PrecisionSource":
                case "LanguageCode":
                    return parseInt(node.firstChild.nodeValue, 10);
                    // Boolean values
                case "AutoRouteToOwnerQueue":
                case "CanBeChanged":
                case "CanTriggerWorkflow":
                case "IsActivity":
                case "IsActivityParty":
                case "IsAvailableOffline":
                case "IsChildEntity":
                case "IsCustomEntity":
                case "IsCustomOptionSet":
                case "IsDocumentManagementEnabled":
                case "IsEnabledForCharts":
                case "IsGlobal":
                case "IsImportable":
                case "IsIntersect":
                case "IsManaged":
                case "IsReadingPaneEnabled":
                case "IsValidForAdvancedFind":
                case "CanBeSecuredForCreate":
                case "CanBeSecuredForRead":
                case "CanBeSecuredForUpdate":
                case "IsCustomAttribute":
                case "IsManaged":
                case "IsPrimaryId":
                case "IsPrimaryName":
                case "IsSecured":
                case "IsValidForCreate":
                case "IsValidForRead":
                case "IsValidForUpdate":
                case "IsCustomRelationship":
                case "CanBeBasic":
                case "CanBeDeep":
                case "CanBeGlobal":
                case "CanBeLocal":
                    return (node.firstChild.nodeValue == "true") ? true : false;
                    //OptionMetadata.Value and BooleanManagedProperty.Value and AttributeRequiredLevelManagedProperty.Value
                case "Value":
                    //BooleanManagedProperty.Value
                    if ((node.firstChild.nodeValue == "true") || (node.firstChild.nodeValue == "false")) {
                        return (node.firstChild.nodeValue == "true") ? true : false;
                    }
                    //AttributeRequiredLevelManagedProperty.Value
                    if (
                 (node.firstChild.nodeValue == "ApplicationRequired") ||
                 (node.firstChild.nodeValue == "None") ||
                 (node.firstChild.nodeValue == "Recommended") ||
                 (node.firstChild.nodeValue == "SystemRequired")
                 ) {
                        return node.firstChild.nodeValue;
                    }
                    else {
                        //OptionMetadata.Value
                        return parseInt(node.firstChild.nodeValue, 10);
                    }
                    break;
                    //String values 
                default:
                    return node.firstChild.nodeValue;
            }

        }

        //Check if it is a known array
        if (_isMetadataArray(_getNodeName(node))) {
            var arrayValue = [];

            for (var i = 0; i < node.childNodes.length; i++) {
                var objectTypeName;
                if ((node.childNodes[i].attributes != null) && (node.childNodes[i].attributes.getNamedItem("i:type") != null)) {
                    objectTypeName = node.childNodes[i].attributes.getNamedItem("i:type").nodeValue.split(":")[1];
                }
                else {

                    objectTypeName = _getNodeName(node.childNodes[i]);
                }

                var b = _objectifyNode(node.childNodes[i]);
                b._type = objectTypeName;
                arrayValue.push(b);

            }

            return arrayValue;
        }

        //Null entity description labels are returned as <label/> - not using i:nil = true;
        if (node.childNodes.length == 0) {
            return null;
        }

        //Otherwise return an object
        var c = {};
        if (node.attributes.getNamedItem("i:type") != null) {
            c._type = node.attributes.getNamedItem("i:type").nodeValue.split(":")[1];
        }
        for (var i = 0; i < node.childNodes.length; i++) {
            if (node.childNodes[i].nodeType == 3) {
                c[_getNodeName(node.childNodes[i])] = node.childNodes[i].nodeValue;
            }
            else {
                c[_getNodeName(node.childNodes[i])] = _objectifyNode(node.childNodes[i]);
            }

        }
        return c;
    };

    function _selectNodes(node, XPathExpression) {
        if (typeof (node.selectNodes) != "undefined") {
            return node.selectNodes(XPathExpression);
        }
        else {
            var output = [];
            var XPathResults = node.evaluate(XPathExpression, node, _NSResolver, XPathResult.ANY_TYPE, null);
            var result = XPathResults.iterateNext();
            while (result) {
                output.push(result);
                result = XPathResults.iterateNext();
            }
            return output;
        }
    };

    function _selectSingleNode(node, xpathExpr) {
        if (typeof (node.selectSingleNode) != "undefined") {
            return node.selectSingleNode(xpathExpr);
        }
        else {
            var xpe = new XPathEvaluator();
            var xPathNode = xpe.evaluate(xpathExpr, node, _NSResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
            return (xPathNode != null) ? xPathNode.singleNodeValue : null;
        }
    };

    function _selectSingleNodeText(node, xpathExpr) {
        var x = _selectSingleNode(node, xpathExpr);
        if (_isNodeNull(x))
        { return null; }
        if (typeof (x.text) != "undefined") {
            return x.text;
        }
        else {
            return x.textContent;
        }
    };

    function _getNodeText(node) {
        if (typeof (node.text) != "undefined") {
            return node.text;
        }
        else {
            return node.textContent;
        }
    };

    function _isNodeNull(node) {
        if (node == null)
        { return true; }
        if ((node.attributes.getNamedItem("i:nil") != null) && (node.attributes.getNamedItem("i:nil").value == "true"))
        { return true; }
        return false;
    };

    function _getNodeName(node) {
        if (typeof (node.baseName) != "undefined") {
            return node.baseName;
        }
        else {
            return node.localName;
        }
    };

    function _setSelectionNamespaces(doc) {
        var namespaces = [
        "xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'",
        "xmlns:a='http://schemas.microsoft.com/xrm/2011/Contracts'",
        "xmlns:i='http://www.w3.org/2001/XMLSchema-instance'",
        "xmlns:b='http://schemas.datacontract.org/2004/07/System.Collections.Generic'",
        "xmlns:c='http://schemas.microsoft.com/xrm/2011/Metadata'"
        ];
        doc.setProperty("SelectionNamespaces", namespaces.join(" "));

    }

    function _NSResolver(prefix) {
        var ns = {
            "s": "http://schemas.xmlsoap.org/soap/envelope/",
            "a": "http://schemas.microsoft.com/xrm/2011/Contracts",
            "i": "http://www.w3.org/2001/XMLSchema-instance",
            "b": "http://schemas.datacontract.org/2004/07/System.Collections.Generic",
            "c": "http://schemas.microsoft.com/xrm/2011/Metadata"
        };
        return ns[prefix] || null;
    };

    function _xmlEncode(strInput) {
        var c;
        var XmlEncode = '';
        if (strInput == null) {
            return null;
        }
        if (strInput == '') {
            return '';
        }
        for (var cnt = 0; cnt < strInput.length; cnt++) {
            c = strInput.charCodeAt(cnt);
            if (((c > 96) && (c < 123)) ||
                     ((c > 64) && (c < 91)) ||
                     (c == 32) ||
                     ((c > 47) && (c < 58)) ||
                     (c == 46) ||
                     (c == 44) ||
                     (c == 45) ||
                     (c == 95)) {
                XmlEncode = XmlEncode + String.fromCharCode(c);
            }
            else {
                XmlEncode = XmlEncode + '&#' + c + ';';
            }
        }
        return XmlEncode;
    };

}).call(SDK.Metadata);

//SDK.Metadata.EntityFilters
// this enum is written this way to enable Visual Studio IntelliSense
SDK.Metadata.EntityFilters.prototype = {
    Default: 1,
    Entity: 1,
    Attributes: 2,
    Privileges: 4,
    Relationships: 8,
    All: 15
};
SDK.Metadata.EntityFilters.Default = 1;
SDK.Metadata.EntityFilters.Entity = 1;
SDK.Metadata.EntityFilters.Attributes = 2;
SDK.Metadata.EntityFilters.Privileges = 4;
SDK.Metadata.EntityFilters.Relationships = 8;
SDK.Metadata.EntityFilters.All = 15;
SDK.Metadata.EntityFilters.__enum = true;
SDK.Metadata.EntityFilters.__flags = true;


//</snippetSDK.Metadata.js>


